//给你一个整数数组 nums 和一个整数 target 。
//
// 向数组中的每个整数前添加 '+' 或 '-' ，然后串联起所有整数，可以构造一个 表达式 ：
//
//
// 例如，nums = [2, 1] ，可以在 2 之前添加 '+' ，在 1 之前添加 '-' ，然后串联起来得到表达式 "+2-1" 。
//
//
// 返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。
//
//
//
// 示例 1：
//
//
//输入：nums = [1,1,1,1,1], target = 3
//输出：5
//解释：一共有 5 种方法让最终目标和为 3 。
//-1 + 1 + 1 + 1 + 1 = 3
//+1 - 1 + 1 + 1 + 1 = 3
//+1 + 1 - 1 + 1 + 1 = 3
//+1 + 1 + 1 - 1 + 1 = 3
//+1 + 1 + 1 + 1 - 1 = 3
//
//
// 示例 2：
//
//
//输入：nums = [1], target = 1
//输出：1
//
//
//
//
// 提示：
//
//
// 1 <= nums.length <= 20
// 0 <= nums[i] <= 1000
// 0 <= sum(nums[i]) <= 1000
// -1000 <= target <= 1000
//
//
// Related Topics 数组与矩阵 动态规划 回溯与递归 👍 1577 👎 0


//leetcode submit region begin(Prohibit modification and deletion)
function findTargetSumWays(nums: number[], target: number): number {


    // 把数组分成两个组合left, right。left + right = sum, left - right = target  =>  left = (sum + target)/2
    const sum: number = nums.reduce((a: number, b: number): number => a + b);
    if ((sum + target) % 2 || Math.abs(target) > sum)  return 0;  // 无解的情况
    const left: number = (sum + target) / 2;

    // 也就是说要达到条件，left（总和）需要为(sum + target) / 2。故就将问题转化为装满容量为left的背包有多少种方法
    /*
     dp[i]表示装满容量为i的背包有多少种方法

     递归公式 dp[j] += dp[j - nums[i]]

     解释：当前值为num[i] => 剩下总容量为left - num[i] 此时dp[left - num[i]]就是装满当前剩余容量的背包有的方法数
     那么递推公式为什么是这些的累加呢？
     dp[j] = dp[j]+dp[j-nums[i]]，表示能凑出和为 j 的方案数应该为：不选 nums[i] 的方案数 dp[j] 加上选择 nums[i] 的方案数 dp[j-nums[i]]。
     */
    const dp: number[] = new Array(left + 1).fill(0);
    dp[0] = 1;  // 装满容量为0的背包有1种方法（什么也不装）
    for (let i: number = 0; i < nums.length; i++) {
        for (let j: number = left; j >= nums[i]; j--) {
            // 大家也可以记住，在求装满背包有几种方法的情况下，递推公式一般为：
            dp[j] += dp[j - nums[i]];
        }
    }
    return dp[left];
};
//leetcode submit region end(Prohibit modification and deletion)
